/************************************************************************/
/* Game                                                                 */
/************************************************************************/
#include "Game/Game Objects/Marios/BaseMario.h"

namespace TD_Game {


	/************************************************************************/
	/* Default definitions                                                  */
	/************************************************************************/


	const unsigned int BaseMario::m_defaultMaxLife = 100;
	const float BaseMario::m_defaultBaseMarioSpeed = (5*screenWidth/1024.0)/frameRate;

	/************************************************************************/
	/* Private functions                                                    */
	/************************************************************************/
	

	int round(float rounded) {
		int intRounded = (int)rounded; 
		if(rounded >= 0) {
			if(rounded - intRounded < 0.5) {
				return(intRounded);
			}
			return(intRounded + 1);
		} else {
			if(rounded - intRounded > -0.5) {
				return(intRounded);
			}
		}
		return(intRounded - 1);

		
	}
	

	void BaseMario::updateDirection(int i, int j) {
		if(j < m_pPathMatrix->getMatrixSize().x - 1 && (*m_pPathMatrix)(i, j + 1) == 1) {
			if(m_currAction != walkingLeft) {
				m_lastAction = m_currAction;
				m_currAction = walkingRight;
				//res_x*A
				
				if((i == 4 && j == 0) || (i == 4 && j == 3) || (i == 0 && j == 6) ) {
					m_nextWaypoint.x = (j + 1) * m_pathSize.x + screenWidth*0.11 + m_pathDeviant + 9;
				} else if (i == 5 && j == 2) {
					m_nextWaypoint.x = (j + 1) * m_pathSize.x + screenWidth*0.11 + m_pathDeviant + 18;
				} else if(i == 4 & j== 6) {
					m_nextWaypoint.x = (j + 1) * m_pathSize.x + screenWidth*0.11 + m_pathDeviant - 9;
				} else {
					m_nextWaypoint.x = (j + 1) * m_pathSize.x + screenWidth*0.11 + m_pathDeviant;
				}
				
				m_dispVector.x = 1;
				m_dispVector.y = 0;
				m_tx = m_ty = 0.0f;
				return;
			}
		} 

		if(i < m_pPathMatrix->getMatrixSize().y - 1  && (*m_pPathMatrix)(i + 1, j) == 1) {
			if(m_currAction != walkingUp) {
				m_lastAction = m_currAction;
				m_currAction = walkingDown;
				//res_x*B
				if((i == 3 && j == 0) ||  (i == 1 && j == 7)) {
					m_nextWaypoint.y = (i + 1) * m_pathSize.y + screenHeight * 0.1341 + m_pathDeviant + 18;
				} else if(i == 3 && j == 6) {
					m_nextWaypoint.y = (i + 1) * m_pathSize.y + screenHeight * 0.1341 + m_pathDeviant + 9;
				} else {
					m_nextWaypoint.y = (i + 1) * m_pathSize.y + screenHeight * 0.1341 + m_pathDeviant;
				}
				m_dispVector.x = 0;
				m_dispVector.y = 1;
				m_tx = m_ty = 0.0f;
				return;
			}
		}
		if(j > 0 && (*m_pPathMatrix)(i, j - 1) == 1) {
			if(m_currAction != walkingRight) {
				m_lastAction = m_currAction;
				m_currAction = walkingLeft;
				//res_x*B

				if((i == 2 && j == 1)) {
					m_nextWaypoint.x = (j - 1)  * m_pathSize.x + screenHeight * 0.1341 + m_pathDeviant + 0.0175*screenWidth;
				} else if (i == 2 && j == 4) {
					m_nextWaypoint.x = (j - 1)  * m_pathSize.x + screenHeight * 0.1341 + m_pathDeviant + 28;
				} else if(i == 2 && j == 7) {
					m_nextWaypoint.x = (j - 1)  * m_pathSize.x + screenHeight * 0.1341 + m_pathDeviant + 9;
				} else {
					m_nextWaypoint.x = (j - 1)  * m_pathSize.x + screenHeight * 0.1341 + m_pathDeviant;
				}
				m_dispVector.x = -1;
				m_dispVector.y = 0;
				m_tx = m_ty = 0.0f;
				return;
			}
		}

		if(i > 0 && (*m_pPathMatrix)(i - 1, j) == 1) {
			if(m_currAction != walkingDown) {
				m_lastAction = m_currAction;
				//res_x*B
				m_nextWaypoint.y = (i - 1)  * m_pathSize.y + screenHeight * 0.1341 + m_pathDeviant;
				m_dispVector.x = 0;
				m_dispVector.y = -1;
				m_tx = m_ty = 0.0f;
				m_currAction = walkingUp;
			}
		}

	}
	
	/************************************************************************/
	/* Constructors                                                         */
	/************************************************************************/

	BaseMario::BaseMario() {
		
	}

	BaseMario::BaseMario(const WaveInfo &gWaveInfo, const Coord2D &g_position, TerrainTilemap * const terrainTilemap, int pathDeviant, baseMarioDirection cDirection) : BaseEntity(g_position) {
		m_waveInfo = gWaveInfo;

		m_pPathMatrix = terrainTilemap->getPathMatrix();

		m_pathSize = terrainTilemap->getTilesize()*3;
		
		m_lastIndex_i = m_lastIndex_j = -9999;
		
		m_baseMarioDirection = cDirection;

		m_isDead = m_isDying = false;

		m_pathDeviant = pathDeviant;
		
		m_isDead = false;
		m_currLife = m_maxLife = m_defaultMaxLife;

		m_currAction = pipeWarping;
		m_internalTimer.start();

		m_nextWaypoint = m_position;

		m_baseMarioSpeed = m_defaultBaseMarioSpeed;

		m_slowAmount = 0;
		m_slowTime = 0;
		m_slowTick = 0;
		m_tick = 0;

		m_updateCount = 0;
		m_tx = m_ty = 0.0f;
		
		m_baseMarioGold = 0;

		m_pHealthBar = new HealthBar(m_position - Coord2D(15, 25), Coord2D(20, 5));
		m_pHealthBar->setHealth(m_currLife/static_cast<float>(m_maxLife));

		m_pJumpSound = TD_Resources::ResourceManager::loadSound("SFX/sounds/Jump.wav");
		if(m_waveInfo.numberOfMarios == 1) {
			m_pBossSound = TD_Resources::ResourceManager::loadSound("SFX/sounds/bosshahaha.wav");
		}
	}


	BaseMario::~BaseMario() {
		if(dynamic_cast<StandardAnimationSet *>(m_pAnimationSet)) {
			Utils::safeDelete<StandardAnimationSet>(dynamic_cast<StandardAnimationSet *>(m_pAnimationSet));
		} else {
			Utils::safeDelete<AnimationSet>(m_pAnimationSet);
		}
		
		Utils::safeDelete<HealthBar>(m_pHealthBar);
	}

	
	/************************************************************************/
	/* Rendering                                                            */
	/************************************************************************/
	void BaseMario::update(unsigned int deltaTime) {
		m_tick += deltaTime;


		if(m_slowAmount > 0) {
			if(m_slowTime < m_tick - m_slowTick) {
				m_slowAmount = 0;
				m_slowTime = 0;
				m_slowTick = 0;
				m_baseMarioSpeed = m_maxBaseMarioSpeed;
			} else {
				m_baseMarioSpeed = m_slowAmount * m_maxBaseMarioSpeed;
			}
		}

		if(isWalking()) {
			if(Coord2D::DistanceBetween(m_position, m_nextWaypoint) < 5.0) {
				int i = round((m_position.y - 0.146492*screenHeight)/ (float) m_pathSize.y );
				int j = round((m_position.x - 0.098696*screenWidth) / (float)  m_pathSize.x);
				updateDirection(i , j);

			}

			Coord2D tempPosition;

			m_tx += (((float) m_dispVector.x) * m_baseMarioSpeed * deltaTime);
			m_ty += (((float) m_dispVector.y) * m_baseMarioSpeed * deltaTime);

			tempPosition = m_position;

			if(m_tx > 1 || m_tx < -1) {
				tempPosition.x += (int) m_tx;
				m_tx -= (int) m_tx;

			}

			if(m_ty > 1 || m_ty < -1) {
				tempPosition.y += (int) m_ty;
				m_ty -= (int) m_ty;
			}


			setPosition(tempPosition);
		} else if(m_currAction == pipeWarping) {
			if(Coord2D::DistanceBetween(m_position, Coord2D(0.054*screenWidth, 0.0869025*screenHeight) - Coord2D(0.013966*screenWidth, 0)) > 5.0*screenWidth/1024.0) {
				m_ty += (-1.0 * 8/60.0 * deltaTime);

				Coord2D tempPosition = m_position;

				if(m_ty > 1 || m_ty < -1) {
					tempPosition.y += (int) m_ty;
					m_ty -= (int) m_ty;
				}

				setPosition(tempPosition);
			} else {
				m_currAction = pipeWaiting;
				m_waitingTicks = 0;
				if(m_waveInfo.numberOfMarios == 1)
					m_pBossSound->playSound(false);
			}
		} else if(m_currAction == pipeWaiting) {
			m_waitingTicks += deltaTime;
			int waitingTime;
			if(m_waveInfo.numberOfMarios == 1) waitingTime = 2000; //Boss
			else waitingTime = 350;
			if(m_waitingTicks > waitingTime) {
				m_currAction = jumpingArising;
				m_jumpingForce = 10*screenHeight/768.0;
				m_jumpingSpeed = 150*screenHeight/768.0;
				m_pJumpSound->playSound(false);
			}
		} else if(m_currAction == jumpingArising) {
			if(Coord2D::DistanceBetween(m_position, Coord2D(0.054*screenWidth, 0.0869025*screenHeight) + Coord2D(0.0446973*screenWidth, 0.0446973*screenWidth)) > 10.0*screenWidth/1024.0) {

				Coord2D tempPosition = m_position;
				
				m_jumpingSpeed -= m_jumpingForce;

				m_tx += ((100 * screenWidth/1024.0) * deltaTime/1000.0);
				m_ty += (-1 * m_jumpingSpeed * deltaTime/1000.0);

				if(m_tx >= 1 || m_tx <= -1) {
					tempPosition.x += (int) m_tx;
					m_tx -= (int) m_tx;

				}

				if(m_ty >= 1 || m_ty <= -1) {
					tempPosition.y += (int) m_ty;
					m_ty -= (int) m_ty;

				}

				setPosition(tempPosition);
			} else {
				m_currAction = walkingRight;
				m_tx = m_ty = 0.0f;
				m_nextWaypoint = m_position;
			}

		} 



		if(m_currAction == idleUp) {
			m_pAnimationSet->setCurrentAnimation("U_idle");
		} else if (m_currAction == idleRight) {
			m_pAnimationSet->setCurrentAnimation("R_idle");
		} else if (m_currAction == pipeWarping || m_currAction == idleDown) { 
			m_pAnimationSet->setCurrentAnimation("R_idle");
		} else if(m_currAction == jumpingArising) {
			m_pAnimationSet->setCurrentAnimation("R_jumping");
			/*m_position += Coord2D(0, -1) * m_baseMarioSpeed;*/
		} else if(m_currAction == walkingUp) {
			m_pAnimationSet->setCurrentAnimation("U_walking");
			/*m_position += Coord2D(0, -1) * m_baseMarioSpeed;*/
		} else if (m_currAction == walkingDown) {
			m_pAnimationSet->setCurrentAnimation("D_walking");
			/*m_position += Coord2D(0, 1) * m_baseMarioSpeed;*/
		} else if (m_currAction == walkingLeft) {
			m_pAnimationSet->setCurrentAnimation("L_walking");
			/*m_position += Coord2D(-1, 0) * m_baseMarioSpeed;*/
		} else if (m_currAction == walkingRight) {
			m_pAnimationSet->setCurrentAnimation("R_walking");
			/*m_position += Coord2D(1, 0) * m_baseMarioSpeed;*/
		} else if (m_currAction == dying) {
			m_pAnimationSet->setCurrentAnimation("Dying");
			m_isDying = true;
			if(m_pAnimationSet->getCurrentAnimation()->isFinished()) {
				m_isDead = true;
			}
		}

	}

	void BaseMario::render(SDL_Surface *const g_destSurface, unsigned int deltaTime) {
		


		if(m_pAnimationSet != NULL) {
			m_pAnimationSet->render(g_destSurface, deltaTime, m_position);
		}
		
		if(m_pHealthBar != NULL) {
			m_pHealthBar->render(g_destSurface, deltaTime);
		}


	}


}